package com.example.translateappjava.Service.YOLOAPI;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONObject;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ImageUploader {
    private final String IP = "http://47.120.15.23:6003/";
    private ExecutorService executorService = Executors.newSingleThreadExecutor();

    private ArrayList<String> URLs;
    private OkHttpClient client = new OkHttpClient();  // OkHttpClient 实例

    private ArrayList<Bitmap> bitmaps;
    private ArrayList<byte[]> bytes;
    private int length = -1;

    private ImageUploadCallback callback;

    // Upload image
    public void uploadImage(Bitmap bitmap, ImageUploadCallback callback) {
        this.callback = callback;  // 保存回调接口
        executorService.submit(() -> {
            String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS").format(new Date());
            String fileName = "upload_image_" + timestamp + ".jpg";
            String uploadUrl = IP + "upload?image=" + fileName;

            HttpURLConnection connection = null;
            try {
                URL url = new URL(uploadUrl);
                connection = (HttpURLConnection) url.openConnection();
                connection.setDoOutput(true);
                connection.setRequestMethod("POST");
                connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=*****");
                bitmaps = new ArrayList<>();
                bytes = new ArrayList<>();
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.JPEG, 40, byteArrayOutputStream);
                byte[] bitmapData = byteArrayOutputStream.toByteArray();

                DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
                outputStream.writeBytes("--*****\r\n");
                outputStream.writeBytes("Content-Disposition: form-data; name=\"image\"; filename=\"" + fileName + "\"\r\n");
                outputStream.writeBytes("Content-Type: image/jpeg\r\n");
                outputStream.writeBytes("\r\n");

                outputStream.write(bitmapData);
                outputStream.writeBytes("\r\n");
                outputStream.writeBytes("--*****--\r\n");
                outputStream.flush();

                int responseCode = connection.getResponseCode();
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    InputStream responseStream = connection.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(responseStream));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        response.append(line);
                    }
                    reader.close();
                    handleServerResponse(response.toString());
                } else {
                    handleErrorResponse(connection.getErrorStream(), bitmap);
                }
            } catch (IOException e) {
                e.printStackTrace();
                handleErrorResponse(connection.getErrorStream(), bitmap);
            }
        });
    }

    private void handleErrorResponse(InputStream errorStream, Bitmap bitmap) {
        // 设置最大重试次数
        final int MAX_RETRY_COUNT = 5;
        final int[] retryCount = {0}; // 用数组来存储重试次数

        executorService.submit(() -> {
            try {
                // 在这里处理错误流，如果需要你可以解析错误信息来决定是否重试
                // 当前假设是网络或服务器问题，直接进行重试

                // 如果重试次数没有超出最大值，则递归调用上传方法进行重试
                if (retryCount[0] < MAX_RETRY_COUNT) {
                    retryCount[0]++; // 增加重试次数
                    Log.d("Upload", "Retrying upload... Attempt " + retryCount[0]);

                    // 重新上传图片
                    uploadImage(bitmap, callback);  // 重新调用上传方法
                } else {
                    Log.e("Upload", "Upload failed after " + retryCount[0] + " attempts.");
                    // 如果达到最大重试次数，通知失败
                    if (callback != null) {
                        callback.onUploadFailed(new IOException("Upload failed after " + MAX_RETRY_COUNT + " attempts"));
                    }
                }
            } catch (Exception e) {
                Log.e("Upload", "Error handling error response: " + e.getMessage());
                if (callback != null) {
                    callback.onUploadFailed(e);  // 如果处理错误时发生异常，调用失败回调
                }
            }
        });
    }

    // Handle server response
    public void handleServerResponse(String serverResponse) {
        Log.d("Upload", "Handling server response...");
        try {
            JSONObject responseJson = new JSONObject(serverResponse);
            if (responseJson.has("generated_images")) {
                JSONArray generatedImages = responseJson.getJSONArray("generated_images");
                length = generatedImages.length();
                Log.d("Upload", "Generated images count: " + generatedImages.length());
                URLs = new ArrayList<String>();
                for (int i = 0; i < generatedImages.length(); i++) {
                    String imagePath = generatedImages.getString(i).replace("output_images", "").replace("\\", "").replace("%5C","");
                    String imageUrl = IP + "download/" + imagePath;
                    // Create a retryCount array for retry logic
                    int[] retryCount = new int[1];  // retryCount[0] will store the retry attempts

                    // Call downloadImage with both parameters (imageUrl and retryCount)
                    downloadImage(imageUrl);
                    System.out.println(imageUrl);
                }
            } else {
                Log.e("Upload", "No 'generated_images' found in server response.");
            }
        } catch (Exception e) {
            Log.e("Upload", "Error processing response: " + e.getMessage());
        }
    }

    // Download image and decode it
    public void downloadImage(String imageUrl) {
        final int MAX_RETRIES = 5;
        final int[] retryCount = {0}; // 使用数组来保存重试次数

        Request request = new Request.Builder()
                .url(imageUrl)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleRetryOrFailure(e, imageUrl);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    try (InputStream inputStream = response.body().byteStream();
                         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {

                        byte[] buffer = new byte[8096];
                        int bytesRead;
                        while ((bytesRead = inputStream.read(buffer)) != -1) {
                            byteArrayOutputStream.write(buffer, 0, bytesRead);
                        }

                        byte[] imageData = byteArrayOutputStream.toByteArray();
                        Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length);

                        if (bitmap != null) {
                            Log.d("Download", "Image downloaded and decoded successfully.");
                            bitmaps.add(bitmap);
                            bytes.add(imageData);
                            URLs.add(imageUrl);
                            // 所有图片都已下载时，调用回调
                            if (bitmaps.size() == length && callback != null) {
                                callback.onUploadComplete(bitmaps, bytes, URLs);
                            }
                        } else {
                            handleRetryOrFailure(new IOException("Failed to decode image"), imageUrl);
                        }
                    } catch (Exception e) {
                        handleRetryOrFailure((IOException) e, imageUrl);
                    }
                } else {
                    handleRetryOrFailure(new IOException("Unexpected response"), imageUrl);
                }
            }

            private void handleRetryOrFailure(IOException e, String imageUrl) {
                if (retryCount[0] < MAX_RETRIES) {
                    retryCount[0]++;
                    Log.d("Download", imageUrl.substring(imageUrl.indexOf("output_image"), imageUrl.indexOf("_202")) + " Retrying... Attempt " + retryCount[0]);
                    downloadImage(imageUrl); // 使用递归方法重新请求
                } else {
                    Log.e("Download", "Failed to download after " + MAX_RETRIES + " retries.");
                    if (callback != null) {
                        callback.onUploadFailed(e); // 上传失败回调
                    }
                }
            }
        });
    }






    // Define callback interface
    public interface ImageUploadCallback {
        void onUploadComplete(ArrayList<Bitmap> bitmaps, ArrayList<byte[]> bytes, ArrayList<String> URLs);
        void onUploadFailed(Exception e);
    }

    // Getters
    public ArrayList<String> getURLs() {
        return URLs;
    }

    public ArrayList<Bitmap> getBitmaps() {
        return bitmaps;
    }

    public ArrayList<byte[]> getBytes() {
        return bytes;
    }
}